package cn.com.dcsgo.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * 对象转换工具
 * TODO 测试
 *
 * @author Dcsgo
 * @since 23/5/2025 下午 3:00
 */

public class ConverterUtils {

    /**
     * 拷贝对象中的属性值，若属性值相同则将目标对象对应的属性值置 null
     *
     * @param source            参考对象
     * @param target            将要将其字段置 null 的对象
     * @param excludeFieldNames 排除置 null 的字段名
     */
    public static void syncFieldsWithNullOnEqual(Object source, Object target, String... excludeFieldNames) {
        if (source == null || target == null) {
            return;
        }
        Set<String> excludeSet = new HashSet<>(Arrays.asList(excludeFieldNames));
        Class<?> sourceClazz = source.getClass();
        Class<?> targetClazz = target.getClass();

        for (Field targetField : getAllFields(targetClazz)) {
            String fieldName = targetField.getName();

            // 跳过静态字段和final字段
            int modifiers = targetField.getModifiers();
            if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
                continue;
            }

            if (excludeSet.contains(fieldName)) {
                continue;
            }
            Field sourceField = getField(sourceClazz, fieldName);
            // 源对象没有该字段，跳过
            if (sourceField == null) {
                continue;
            }

            targetField.setAccessible(true);
            sourceField.setAccessible(true);

            try {
                Object sVal = sourceField.get(source);
                Object tVal = targetField.get(target);

                if (Objects.equals(sVal, tVal)) {
                    targetField.set(target, null);
                } else {
                    targetField.set(target, sVal);
                }
            } catch (Exception e) {
                throw new RuntimeException("Failed to sync field " + fieldName, e);
            }
        }
    }

    /**
     * 获取类的所有字段(支持父类字段)
     *
     * @param clazz 类对象
     * @return 类的所有字段, 包含其父类字段
     */
    private static List<Field> getAllFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        while (clazz != null && clazz != Object.class) {
            fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
            clazz = clazz.getSuperclass();
        }
        return fields;
    }

    /**
     * 获取类的字段(包含父类字段)
     *
     * @param clazz     类对象
     * @param fieldName 字段名
     * @return 类的字段, 不存在返回 null
     */
    private static Field getField(Class<?> clazz, String fieldName) {
        while (clazz != null && clazz != Object.class) {
            try {
                return clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        }
        return null;
    }
}
